﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WiiGeeDotNet.events;
using System.Xml.Linq;
using System.Globalization;

namespace WiiGeeDotNet.logic
{

  /// <summary>
  /// This class analyzes the WiimoteAccelerationEvents emitted from a Wiimote
  /// and further creates and manages the different models for each type
  /// of gesture. 
  /// </summary>
  public class TriggeredProcessingUnit : ProcessingUnit
  {
    // gesturespecific values
    private Gesture m_current; // current gesture

    private List<Gesture> m_trainsequence;

    public List<Gesture> Trainsequence
    {
      get { return m_trainsequence; }
    }


    // State variables
    private bool m_learning = false;
    private bool m_analyzing = false;

    public TriggeredProcessingUnit()
      : base()
    {
      m_learning = false;
      m_analyzing = false;
      m_current = new Gesture();
      m_trainsequence = new List<Gesture>();

    }

    public Dictionary<int, GestureModel> GestureModels
    {
      get { return m_classifier.GestureModels; }
    }


    /// <summary>
    /// Since this class implements the WiimoteListener this procedure is
    /// necessary. It contains the filtering (directional equivalence filter)
    /// and adds the incoming data to the current motion, we want to train
    /// or recognize.
    /// </summary>
    /// <param name="_event">The acceleration event which has to be processed by the
    /// directional equivalence filter and which has to be added to the current
    /// motion in recognition or training process.</param>
    public override void AccelerationReceived(AccelerationEvent _event)
    {
      if (this.m_learning || this.m_analyzing)
      {
        this.m_current.Add(_event); // add event to gesture			
      }
    }

    public override void MotionStartReceived(MotionStartEvent _event)
    {
      //this.handleStartEvent(_event);
    }

    public override void MotionStopReceived(MotionStopEvent _event)
    {
      //this.handleStopEvent(_event);
    }

    public void StartLearning()
    {
      if (!this.m_analyzing && !this.m_learning)
      {
        Console.WriteLine("Training started!");
        this.m_learning = true;
        this.FireStateEvent(1);
      }
    }
    public int FinishTraining(String _name)
    {
      return FinishTraining(_name, true);
    }

    public int FinishTraining(String _name, bool _saveGesture)
    {
      if (_saveGesture)
      {
        if (this.m_trainsequence.Count > 0)
        {
          Console.WriteLine("Training the model with " + this.m_trainsequence.Count + " gestures...");
          this.FireStateEvent(1);
          this.m_learning = true;


          //get the next available id
          int id = 0;
          if (m_classifier.GestureModels.Count > 0)
          {
            id = m_classifier.GestureModels.Last().Key + 1;
          }
          GestureModel m = new GestureModel(id);
          m.Name = _name;
          m.Train(this.m_trainsequence);
          m.Print();


          this.m_classifier.AddGestureModel(m);

          this.m_trainsequence = new List<Gesture>();
          this.m_learning = false;
          return m.Id;
        }
        else
        {
          Console.WriteLine("There is nothing to do. Please record some gestures first.");
          return -99;
        }
      }
      else
      {
        this.m_trainsequence = new List<Gesture>();
        this.m_learning = false;
        return -99;
      }
    }

    public void StartAnalyzing()
    {
      if (!this.m_analyzing && !this.m_learning)
      {
        Console.WriteLine("Recognition started!");
        this.m_analyzing = true;
        this.FireStateEvent(2);
      }
    }

    public void StopLearning()
    {
      if (this.m_learning)
      { // button release and state=learning, stops learning
        if (this.m_current.GetCountOfData() > 0)
        {
          Console.WriteLine("Finished recording (training)...");
          Console.WriteLine("Data: " + this.m_current.GetCountOfData());
          Gesture gesture = new Gesture(this.m_current);
          this.m_trainsequence.Add(gesture);
          this.m_current = new Gesture();
          this.m_learning = false;
        }
        else
        {
          Console.WriteLine("There is no data.");
          Console.WriteLine("Please train the gesture again.");
          this.m_learning = false; // ?
        }
      }
    }

    public void StopAnalyzing()
    {
      if (this.m_current.GetCountOfData() > 0)
      {
        Console.WriteLine("Finished recording (recognition)...");
        Console.WriteLine("Compare gesture with " + m_classifier.GestureModels.Count + " other gestures.");
        Gesture gesture = new Gesture(this.m_current);

        GestureModel recognized = m_classifier.ClassifyGesture(gesture);
        if (recognized != null)
        {
          double recogprob = this.m_classifier.GetLastProbability();
          this.FireGestureEvent(recognized.Id, recognized.Name, recogprob);
          Console.WriteLine("######");
          Console.WriteLine("Gesture No. " + recognized.Id + "(" + recognized.Name + ") recognized: " + recogprob);
          Console.WriteLine("######");
        }
        else
        {
          this.FireGestureEvent(-99, "", 0);
          this.FireStateEvent(0);
          Console.WriteLine("######");
          Console.WriteLine("No gesture recognized.");
          Console.WriteLine("######");
        }

        this.m_current = new Gesture();
        this.m_analyzing = false;
      }
      else
      {
        Console.WriteLine("There is no data.");
        Console.WriteLine("Please recognize the gesture again.");
        this.m_analyzing = false; // ?
      }
    }

    public override String GetGestureData(int _id)
    {
      GestureModel g = m_classifier.GestureModels[_id];
      if (g != null)
      {
        return g.GetGestureData();
      }
      else
      {
        return null;
      }
    }


    public override int AddGesture(String _data)
    {
      //get the next available id
      int id = 0;
      if (m_classifier.GestureModels.Count > 0)
      {
        id = m_classifier.GestureModels.Last().Key + 1;
      }
      //add the new gesture
      GestureModel gest = new GestureModel(id, _data);
      m_classifier.AddGestureModel(gest);
      return id;
    }

    internal void RemoveGesture(int _id)
    {
      if (m_classifier.GestureModels.ContainsKey(_id))
      {
        m_classifier.GestureModels.Remove(_id);
      }
    }
  }
}